import socket
import select

def sendMes(socket,recv_data):
    print("接收到来自客户端发送过来的消息： %s" % recv_data)
    response_content = "hello world"
    response_header = "HTTP/1.1 200 OK\r\n"
    response_header += "Content-Length:%d\r\n" % len(response_content) # 通过设置Content-Length来表现出服务器响应内容结束，而不需要调用socket.close()关闭这次服务
    response_header += "\r\n"

    response = response_header + response_content
    socket.send(response.encode('utf-8'))

def main():
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    tcp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放，这样就保证了，下次运行程序时，不会出现端口被占用的情况
    tcp_socket.bind(('127.0.0.1',3000))
    tcp_socket.listen(128)
    tcp_socket.setblocking(False) # 设置套接字为非堵塞的方式
    
    # 创建一个epoll对象
    epl = select.epoll()

    # 将监听套接字对应的fd(文件描述符)注册到epoll中
    epl.register(tcp_socket.fileno(),select.EPOLLIN)

    fd_event_dict = dict()

    while True:

        fd_event_list = epl.poll() # 默认会堵塞，直到os监测到数据到来 通过事件通知方式 告诉这个程序 此时才会解堵塞

        # [(fd,event),(套接字对应的文件描述符)]
        for fd,event in fd_event_list:
            # 等待新客户端的链接
            if fd == tcp_socket.fileno():
                new_client_socket,client_addr = tcp_socket.accept()
                epl.register(new_client_socket.fileno(),select.EPOLLIN)
                fd_event_dict[new_client_socket.fileno()] = new_client_socket
            elif event == select.EPOLLIN:
                # 判断已经链接的客户端是否有数据发送过来
                recv_data = fd_event_dict[fd].recv(1024).decode("utf-8")
                if recv_data:
                    sendMes(fd_event_dict[fd],recv_data)
                else:
                    fd_event_dict[fd].close()
                    epl.unregister(fd)
                    del fd_event_dict[fd]
                    
    tcp_socket.close()

if __name__ == "__main__":
    main()